package day29.homework;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * 图片复制程序
 * 将img.jpg文件复制10份，分别命名为img_copy1.jpg到img_copy10.jpg
 * 
 * 程序功能说明:
 * 1. 读取指定路径的源图片文件
 * 2. 创建10个副本文件，文件名分别为img_copy1.jpg到img_copy10.jpg
 * 3. 使用缓冲流提高文件复制的IO性能
 * 4. 统计复制成功的文件数量并输出结果
 */
public class hw8 {
    
    /**
     * 程序入口点 - main方法
     * 这是Java程序执行的起点，JVM会调用这个方法开始执行程序
     * 
     * @param args 命令行参数数组，用于接收从命令行传入的参数
     *            在这个程序中未使用该参数
     */
    public static void main(String[] args) {
        // 定义源文件名和目标文件名的前缀
        // sourceFileName变量存储原始图片文件的完整路径
        // 这个路径指向需要被复制的源文件
        String sourceFileName = "D:/jd/day29/homework/img.jpg";
        
        // 记录复制成功的文件数量
        // successCount变量用于统计成功复制的文件数量
        // 初始值为0，每成功复制一个文件就加1
        int successCount = 0;
        
        // 在控制台输出提示信息，告知用户程序开始执行复制操作
        // System.out.println是向标准输出流打印信息的方法
        System.out.println("开始复制图片...");
        
        // 循环复制10次
        // 使用for循环从1到10，依次创建10个副本文件
        // 循环变量i从1开始，到10结束（包含10），每次循环后i自增1
        for (int i = 1; i <= 10; i++) {
            // 构造目标文件名
            // 使用字符串拼接的方式构造目标文件名
            // 例如当i=1时，targetFileName="img_copy1.jpg"
            // 当i=2时，targetFileName="img_copy2.jpg"，以此类推
            String targetFileName = "img_copy" + i + ".jpg";
            
            // 调用复制方法执行文件复制操作
            // copyFile方法返回boolean值表示复制是否成功
            // 如果返回true表示复制成功，则执行if代码块内的操作
            if (copyFile(sourceFileName, targetFileName)) {
                // 复制成功时，将成功计数器加1
                successCount++;
                // 在控制台输出成功创建的文件名，告知用户该文件已成功创建
                System.out.println("成功创建: " + targetFileName);
            } else {
                // 复制失败时，在控制台输出失败的文件名
                // System.err.println用于向标准错误流输出错误信息，通常以红色显示
                System.out.println("创建失败: " + targetFileName);
            }
        }
        
        // 所有文件复制操作完成后，输出最终的统计结果
        // 使用字符串拼接将successCount变量的值插入到输出信息中
        System.out.println("复制完成！成功复制 " + successCount + " 个文件。");
    }
    
    /**
     * 复制文件方法
     * 该方法使用缓冲流实现高效的文件复制功能
     * 利用try-with-resources语句自动管理资源，确保流在使用完毕后正确关闭
     * 
     * @param sourceFile 源文件路径 - 需要被复制的原始文件的完整路径
     * @param targetFile 目标文件路径 - 复制后新文件的完整路径
     * @return 复制成功返回true，失败返回false
     *         boolean类型的返回值用于告知调用者操作是否成功
     */
    public static boolean copyFile(String sourceFile, String targetFile) {
        // 使用BufferedInputStream和BufferedOutputStream以提高IO性能
        // try-with-resources语法确保流在使用完毕后自动关闭，即使发生异常也会关闭
        // BufferedInputStream为FileInputStream添加缓冲功能，提高读取效率
        // BufferedOutputStream为FileOutputStream添加缓冲功能，提高写入效率
        try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(sourceFile));
             BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(targetFile))) {
            
            // 定义缓冲区大小为8KB (8192字节)
            // buffer数组作为数据传输的缓冲区，避免频繁的磁盘IO操作
            // 8KB是常用的缓冲区大小，能够在内存占用和性能之间取得较好平衡
            byte[] buffer = new byte[8192];
            // bytesRead变量用于存储每次实际读取的字节数
            // 当读取到文件末尾时，read方法会返回-1
            int bytesRead;
            
            // 循环读取并写入，直到文件结束
            // bis.read(buffer)方法从输入流中读取最多buffer.length个字节到buffer数组中
            // 返回实际读取的字节数，如果已到达流末尾则返回-1
            // 当返回值不等于-1时，表示还有数据可以读取，继续循环
            while ((bytesRead = bis.read(buffer)) != -1) {
                // 将缓冲区中的数据写入到输出流
                // bos.write(buffer, 0, bytesRead)方法将buffer数组中从索引0开始的bytesRead个字节写入输出流
                // 使用bytesRead而不是buffer.length是为了确保只写入实际读取到的数据
                // 避免写入buffer中可能存在的旧数据
                bos.write(buffer, 0, bytesRead);
            }
            
            // 强制刷新缓冲区，确保所有数据都写入目标文件
            // flush方法将缓冲区中所有缓冲的数据立即写入目标文件
            // 虽然close方法也会自动刷新，但显式调用flush是一个好习惯
            bos.flush();
            
            // 文件复制完成，返回true表示操作成功
            return true;
        } catch (IOException e) {
            // 捕获IO异常，当文件操作过程中发生错误时会执行这里的代码
            // 例如源文件不存在、目标文件无法创建、磁盘空间不足等情况
            // 在控制台输出详细的错误信息，帮助调试问题
            System.err.println("复制文件时发生错误: " + e.getMessage());
            // 返回false表示文件复制操作失败
            return false;
        }
    }
}